package com.itheima.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itheima.common.constants.BusinessConstants;
import com.itheima.common.enums.HttpCodeEnum;
import com.itheima.common.exception.LeadNewsException;
import com.itheima.common.util.RequestContextUtil;
import com.itheima.common.vo.PageResultVo;
import com.itheima.wemedia.dto.WmNewsCanlDto;
import com.itheima.wemedia.dto.WmNewsContentNodeDto;
import com.itheima.wemedia.dto.WmNewsDtoSave;
import com.itheima.wemedia.dto.WmNewsPageReqDto;
import com.itheima.wemedia.mapper.WmMaterialMapper;
import com.itheima.wemedia.mapper.WmNewsMapper;
import com.itheima.wemedia.mapper.WmNewsMaterialMapper;
import com.itheima.wemedia.mapper.WmUserMapper;
import com.itheima.wemedia.pojo.WmMaterial;
import com.itheima.wemedia.pojo.WmNews;
import com.itheima.wemedia.pojo.WmNewsMaterial;
import com.itheima.wemedia.pojo.WmUser;
import com.itheima.wemedia.service.WmNewsService;
import com.itheima.wemedia.vo.WmNewsVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @version 1.0
 * @description <p>自媒体图文内容信息 业务实现</p>
 * @package com.itheima.wemedia.service.impl
 */
@Service
public class WmNewsServiceImpl extends ServiceImpl<WmNewsMapper, WmNews> implements WmNewsService {


    @Autowired
    private WmNewsMaterialMapper wmNewsMaterialMapper;

    @Autowired
    private WmMaterialMapper wmMaterialMapper;

    @Autowired
    private KafkaTemplate kafkaTemplate;

    @Autowired
    private WmUserMapper wmUserMapper;


    /**
     * 文章内容发布
     *
     * @param dto
     * @param draft
     * @return
     */
    @Override
    @Transactional
    public Long submit(WmNewsDtoSave dto, Boolean draft) {
        if (null == dto || null == draft) {
            throw new LeadNewsException(HttpCodeEnum.PARAM_REQUIRE);
        }
        //=====================保存数据到文章表中 wm_news=========================
        WmNews pojo = new WmNews();
        BeanUtils.copyProperties(dto, pojo);
        pojo.setUserId(RequestContextUtil.getUserId());
        pojo.setEnable(BusinessConstants.WmNewsConstants.ENABLE_OFF);

        //1.如果传过来的type=-1，表示自动主图，需要获取内容中的图片，根据图片的数量来设置type的值
        List<String> contentImages = addContentImagesPath(dto);
        if (dto.getType() == BusinessConstants.WmNewsConstants.TYPE_AUTO) {
            setWmNewsType(pojo, dto, contentImages);
        }
        //2.根据draft的值来设置status的值。如果为true设置为0，false设置为1
        if (draft) {
            pojo.setStatus(BusinessConstants.WmNewsConstants.STATUS_DRAFT);   //表示为草稿
        } else {
            pojo.setStatus(BusinessConstants.WmNewsConstants.STATUS_SUBMIT); //表示待审核
            pojo.setSubmitedTime(LocalDateTime.now()); //提交时间
            //发布时间
            if (null==dto.getPublishTime()){
                pojo.setPublishTime(LocalDateTime.now());
            }
        }
        //3.设置内容中的图片，路径以逗号分割
        List<String> images = dto.getImages();
        //如果图片不为空，路径以逗号分割
        if (!CollectionUtils.isEmpty(images)) {
            String imageList = String.join(",", images);
            pojo.setImages(imageList);
        }

        //4.保存文章到文章库中（如果文章id存在，则更新文章库，并删除文章与素材中间表的数据 ，如果不存在，就添加文章）
        if (dto.getId() != null) {
            //如果文章id存在，则更新文章库
            updateById(pojo);
            //并删除文章与素材中间表的数据
            removeWmNewsMaterial(dto.getId());
        } else {
            pojo.setCreatedTime(LocalDateTime.now());//创建时才有时间
            save(pojo);
        }



        //=====================保存数据到文章和素材中间表中=========================
        addWmNewsMaterial(pojo, contentImages);
        if (pojo.getStatus() == BusinessConstants.WmNewsConstants.STATUS_SUBMIT) {
            kafkaTemplate.send(BusinessConstants.MqConstants.WM_NEWS_AUTO_SCAN_TOPIC, pojo.getId().toString());
        }

        return pojo.getId();
    }

    /**
     * 删除文章与素材中间表
     *
     * @param id
     */
    private void removeWmNewsMaterial(Long id) {
        if (null == id) {
            throw new LeadNewsException("文章id不存在");
        }
        LambdaQueryWrapper<WmNewsMaterial> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(WmNewsMaterial::getNewsId, id);
        wmNewsMaterialMapper.delete(wrapper);
    }

    /**
     * 保存数据到文章和素材中间表中
     *
     * @param pojo
     * @param contentImages
     */
    private void addWmNewsMaterial(WmNews pojo, List<String> contentImages) {
        //图片可能来源于2个地方
        //一个来源是封面（主图），由前端传来的images中提供图片的全路径 ，需要去掉请求地址和端口，得到文件id ：fileId
        String images = pojo.getImages();
        if (!StringUtils.isEmpty(images)) {
            String[] urlAll = images.split(",");
            List<String> list = Arrays.asList(urlAll);
            saveRelationship(pojo, list, BusinessConstants.WmNewsConstants.WM_COVER_REFERENCE);
        }

        //第二个来源是文章中的内容content，前端传过来的是全路径，需要去掉请求地址和端口，得到文件id ：fileId
        //1.得到文件id，根据文件id去素材库中查询素材表，得到素材的id
        //2.将素材id和文章id存入到文章与素材中间表中，并设置type=0
        saveRelationship(pojo, contentImages, BusinessConstants.WmNewsConstants.WM_CONTENT_REFERENCE);
    }

    private void saveRelationship(WmNews pojo, List<String> list, int type) {
        for (String urlOne : list) {
            String url = removePrefix(urlOne);
            //1.得到文件id，根据文件id去素材库中查询素材表，得到素材的id
            long wmMaterialId = getWmMaterialId(url);
            //2.将素材id和文章id存入到文章与素材中间表中，并设置type=1
            WmNewsMaterial wmNewsMaterial = new WmNewsMaterial();
            wmNewsMaterial.setNewsId(pojo.getId());
            wmNewsMaterial.setMaterialId(wmMaterialId);
            wmNewsMaterial.setType(type);
            wmNewsMaterial.setOrd(1);
            wmNewsMaterialMapper.insert(wmNewsMaterial);
        }
    }

    /**
     * 根据图片id查询素材表得到素材id
     *
     * @param url
     * @return
     */
    private long getWmMaterialId(String url) {
        LambdaQueryWrapper<WmMaterial> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(WmMaterial::getUrl, url);
        WmMaterial wmMaterial = wmMaterialMapper.selectOne(wrapper);
        if (null == wmMaterial) {
            throw new LeadNewsException("查询不到对应的素材" + url);
        }
        return wmMaterial.getId();
    }

    /**
     * 对type=-1 自动主图的处理
     *
     * @param pojo
     * @param dto
     * @param contentImages
     */
    private void setWmNewsType(WmNews pojo, WmNewsDtoSave dto, List<String> contentImages) {
        //得到内容中图片的数量
        int size = contentImages.size();
        //根据图片数量设置type
        if (0 == size) {
            pojo.setType(BusinessConstants.WmNewsConstants.TYPE_NONE_IMG);
            pojo.setImages("");
            dto.setImages(null);
        } else if (size < 3) {
            pojo.setType(BusinessConstants.WmNewsConstants.TYPE_SINGLE_IMG);
            dto.setImages(contentImages.stream().limit(1).collect(Collectors.toList()));
        } else {
            pojo.setType(BusinessConstants.WmNewsConstants.TYPE_MULTIPLE_IMG);
            dto.setImages(contentImages.stream().limit(3).collect(Collectors.toList()));
        }

    }

    /**
     * 获取文章内容中的图片地址
     *
     * @param dto
     * @return
     */
    private List<String> addContentImagesPath(WmNewsDtoSave dto) {
        String content = dto.getContent();
        List<WmNewsContentNodeDto> contentNodeDtoList = JSON.parseArray(content, WmNewsContentNodeDto.class);
        List<String> contentImagesUrl = contentNodeDtoList.stream()
                .filter(n -> BusinessConstants.WmNewsConstants.CONTENT_IMAGE.equals(n.getType()))
                .map(WmNewsContentNodeDto::getValue).collect(Collectors.toList());

        return contentImagesUrl;
    }

    /**
     * 去除请求ip和端口的方法
     *
     * @param url
     * @return
     */
    private static String removePrefix(String url) {
        //http://192.168.211.128:8080/group1/M00/00/00/wKjTgGK4BGuASyi-AAiWSBNgF8M620.png
        //http://192.168.211.128/group1/M00/00/00/wKjTgGK4BGuASyi-AAiWSBNgF8M620.png
        //http://127.0.0.1/group1/M00/00/00/wKjTgGK4BGuASyi-AAiWSBNgF8M620.png
        return url.replaceAll("http://((\\d){1,3}\\.){3}(\\d){1,3}:?(\\d){0,5}\\/", "");
    }


    /**
     * @param dto
     * @return
     */
    @Override
    public PageResultVo listPage(WmNewsPageReqDto dto) {
        if (null == dto) {
            throw new LeadNewsException(HttpCodeEnum.PARAM_REQUIRE);
        }
        //构建分页参数对象
        IPage<WmNews> pageInfo = new Page<>(dto.getPage(), dto.getSize());
        //构建条件
        LambdaQueryWrapper<WmNews> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(null != dto.getChannelId(), WmNews::getChannelId, dto.getChannelId());
        wrapper.like(null != dto.getKeyword(), WmNews::getTitle, dto.getKeyword());
        wrapper.eq(null != dto.getStatus(), WmNews::getStatus, dto.getStatus());
        wrapper.ge(null != dto.getBeginPubDate(), WmNews::getPublishTime, dto.getBeginPubDate());
        wrapper.le(null != dto.getEndPubDate(), WmNews::getPublishTime, dto.getEndPubDate());
        //查询
        page(pageInfo, wrapper);
        //构建对象返回
        return PageResultVo.pageResult(dto.getPage(), dto.getSize(), pageInfo.getTotal(), pageInfo.getRecords());
    }

    /**
     * 通过id删除文章
     *
     * @param wmNewsId
     */
    @Override
    @Transactional
    public void deleteById(Long wmNewsId) {
        if (null == wmNewsId) {
            throw new LeadNewsException(HttpCodeEnum.PARAM_REQUIRE);
        }

        //先查询文章，如果status=9或者enable=1，表示文章已发布或者上架不能删除
        WmNews wmNews = getById(wmNewsId);
        if (BusinessConstants.WmNewsConstants.STATUS_PUBLISHED == wmNews.getStatus()
                || BusinessConstants.WmNewsConstants.ENABLE_ON == wmNews.getEnable()
        ) {
            throw new LeadNewsException("文章已上架或者已发布不能删除");
        }
        //删除文章表
        removeById(wmNewsId);
        //删除文章与素材中间表
        removeWmNewsMaterial(wmNewsId);
    }

    /**
     * 文章上下架
     *
     * @param map
     */
    @Override
    public void downOrUp(Map<String, Integer> map) {

        //上下架修改enable  1为上架，0为下架
        //获取参数
        Integer id = map.get("id");
        Integer enable = map.get("enable");

        if (null == id || null == enable) {
            throw new LeadNewsException(HttpCodeEnum.PARAM_REQUIRE);
        }
        //先根据id查询文章，判断是不是处于已发布的状态status=9，只有处于这个状态时才可以上下架
        WmNews wmNews = getById(id);
        if (BusinessConstants.WmNewsConstants.STATUS_PUBLISHED != wmNews.getStatus()) {
            throw new LeadNewsException("文章未发布禁止上下架!");
        }

        //如果文章是要下架，还得修改status=1
        if (BusinessConstants.WmNewsConstants.ENABLE_OFF == enable) {

            wmNews.setStatus(BusinessConstants.WmNewsConstants.STATUS_SUBMIT);
        }

        wmNews.setEnable(enable);
        boolean flag = updateById(wmNews);
        //文章上下架同步
        if (flag){
            //获得文章微服务中的文章id
            Long articleId = wmNews.getArticleId();
            //获得文章上下架的状态
            //组合上传到Kafka中
            Map<String ,Long> uploadMap =new HashMap<>();
            uploadMap.put("articleId",articleId);
            uploadMap.put("enable",enable.longValue());
            //上传kafka
            kafkaTemplate.send(BusinessConstants.MqConstants.WM_NEWS_DOWN_OR_UP_TOPIC,JSON.toJSONString(uploadMap));
        }
    }

    /**
     * 后台管理： 文章人工审核，分页查询
     *
     * @param dto
     * @return
     */
    @Override
    public PageResultVo<WmNewsVo> wmNewsPageAll(WmNewsPageReqDto dto) {
        //构建分页参数
        IPage<WmNews> pageInfo = new Page<>(dto.getPage(), dto.getSize());
        //构建条件对象
        LambdaQueryWrapper<WmNews> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(null != dto.getStatus(), WmNews::getStatus, dto.getStatus());
        wrapper.like(!StringUtils.isEmpty(dto.getTitle()), WmNews::getTitle, dto.getTitle());
        //查询
        page(pageInfo, wrapper);

        List<WmNewsVo> list = new ArrayList<>();
        //先判断
        if (!StringUtils.isEmpty(pageInfo.getRecords())) {
            //通过文章id查询作者名称，添加到返回对象中
            List<Long> userIds = pageInfo.getRecords().stream().map(WmNews::getUserId).collect(Collectors.toList());
            //查询作者名称
            List<WmUser> wmUsers = wmUserMapper.selectBatchIds(userIds);
            Map<Long, WmUser> userNameMap = wmUsers.stream().collect(Collectors.toMap(WmUser::getId,  Function.identity()));
            list= pageInfo.getRecords().stream().map(r->WmNewsVo.build(r,userNameMap.get(r.getUserId()))).collect(Collectors.toList());
        }
        return PageResultVo.pageResult(dto.getPage(), dto.getSize(), pageInfo.getTotal(), list);
    }

    /**
     * 后台管理： 文章人工审核，文章审核通过
     *
     * @param dto
     * @return
     */
    @Override
    public boolean authPass(WmNewsCanlDto dto) {
        Long wmNewsId = dto.getId();
        if (null == wmNewsId) {
            throw new LeadNewsException(HttpCodeEnum.PARAM_REQUIRE);
        }
        //查询文章信息得到文章状态，判断文章状态=3就修改
        WmNews wmNews = getById(wmNewsId);
        if (BusinessConstants.WmNewsConstants.STATUS_MANUAL == wmNews.getStatus()) {
            WmNews pojo = new WmNews();
            pojo.setId(dto.getId());
            pojo.setStatus(BusinessConstants.WmNewsConstants.STATUS_MANUAL_PASS);
            if (updateById(pojo)) {
                return true;
            }
            return false;
        }

        return false;
    }

    /**
     * 后台管理： 文章人工审核，文章审核驳回
     *
     * @param dto
     * @return
     */
    @Override
    public boolean authFail(WmNewsCanlDto dto) {
        Long wmNewsId = dto.getId();
        String msg = dto.getMsg();
        if (null == wmNewsId || null == msg) {
            throw new LeadNewsException(HttpCodeEnum.PARAM_REQUIRE);
        }
        //查询文章信息得到文章状态，判断文章状态=3就修改
        WmNews wmNews = getById(wmNewsId);
        if (BusinessConstants.WmNewsConstants.STATUS_MANUAL == wmNews.getStatus()) {
            WmNews pojo = new WmNews();
            pojo.setId(dto.getId());
            pojo.setStatus(BusinessConstants.WmNewsConstants.STATUS_FAIL);
            pojo.setReason(msg);
            if (updateById(pojo)) {
                return true;
            }
            return false;
        }

        return false;
    }

    /**
     * 后台管理： 文章人工审核，查询文章详情
     *
     * @param wmNewsId
     * @return
     */

    @Override
    public WmNewsVo getWmNewsOne(Long wmNewsId) {
        if (null == wmNewsId) {
            throw new LeadNewsException(HttpCodeEnum.PARAM_REQUIRE);
        }
        WmNews wmNews = getById(wmNewsId);
        if (null != wmNews) {
            Long userId = wmNews.getUserId();
            WmUser wmUser = wmUserMapper.selectById(userId);
            //TODO有问题
            return WmNewsVo.build(wmNews,wmUser);
        }
        return null;
    }

    /**
     * 远程调用自媒体微服务查询文章信息  ————文章同步
     *
     * @param dto ：为了做分片处理
     * @return
     */
    @Override
    public List<WmNewsVo> syncArticleTask(WmNewsPageReqDto dto) {

        //构建查询条件，状态为8，和发布时间小于当前时间
        //LambdaQueryWrapper<WmNews> wrapper = new LambdaQueryWrapper<>();
        //wrapper.le(WmNews::getPublishTime,LocalDateTime.now());
        //wrapper.in(WmNews::getStatus,BusinessConstants.WmNewsConstants.STATUS_PASS,BusinessConstants.WmNewsConstants.STATUS_MANUAL_PASS);
        //List<WmNews> wmNewsList = list(wrapper);

        List<WmNews> wmNewsList = query().le(null!=dto.getEndPubDate(),"publish_time", dto.getEndPubDate())
                .in("status", BusinessConstants.WmNewsConstants.STATUS_PASS,BusinessConstants.WmNewsConstants.STATUS_MANUAL_PASS)
                .list();


        //得到作者id，通过作者id得到作者名称
        List<WmNewsVo> list =new ArrayList<>();
        if (!CollectionUtils.isEmpty(wmNewsList)){
            List<Long> wmUserIds = wmNewsList.stream().map(WmNews::getUserId).collect(Collectors.toList());
            //查询作者名称
            List<WmUser> wmUsers = wmUserMapper.selectBatchIds(wmUserIds);
            Map<Long, WmUser> userNameMap = wmUsers.stream().collect(Collectors.toMap(WmUser::getId,  Function.identity()));
           list= wmNewsList.stream().map(r->WmNewsVo.build(r,userNameMap.get(r.getUserId()))).collect(Collectors.toList());

        }

        return list;
    }
}
